package com.carbohydrate42.kotlin_compose_demo.compose

import android.content.Context
import android.net.nsd.NsdManager
import android.net.nsd.NsdManager.DiscoveryListener
import android.net.nsd.NsdServiceInfo
import android.util.Log
import androidx.compose.foundation.layout.Column
import androidx.compose.material3.Divider
import androidx.compose.material3.Text
import androidx.compose.material3.TextButton
import androidx.compose.runtime.Composable
import androidx.compose.runtime.mutableStateListOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.tooling.preview.Preview
import com.carbohydrate42.kotlin_compose_demo.util.DebugUtil
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext

/**
 * 服务发现
 */
suspend fun mdnsDiscovery(context: Context, onInfoChange: (info: String) -> Unit) {
    val nsdManager: NsdManager = context.getSystemService(Context.NSD_SERVICE) as NsdManager

    val discoveryListener = object : DiscoveryListener {
        override fun onStartDiscoveryFailed(p0: String?, p1: Int) {
            Log.i("LANServiceDiscovery", "onStartDiscoveryFailed : $p0")
            onInfoChange("onStartDiscoveryFailed $p0")
        }

        override fun onStopDiscoveryFailed(p0: String?, p1: Int) {
            Log.i("LANServiceDiscovery", "onStopDiscoveryFailed : $p0")
            onInfoChange("onStopDiscoveryFailed $p0")
        }

        override fun onDiscoveryStarted(p0: String?) {
            Log.i("LANServiceDiscovery", "onDiscoveryStarted : $p0")
            onInfoChange("onDiscoveryStarted $p0")
        }

        override fun onDiscoveryStopped(p0: String?) {
            Log.i("LANServiceDiscovery", "onDiscoveryStopped : $p0")
            onInfoChange("onDiscoveryStopped $p0")
        }

        override fun onServiceFound(p0: NsdServiceInfo?) {
            Log.i("LANServiceDiscovery", "onServiceFound : $p0")
            onInfoChange(
                """
                onServiceFound
                serviceName : ${p0?.serviceName}
                serviceType : ${p0?.serviceType}
                hostAddress : ${p0?.host?.hostAddress}
                port : ${p0?.port}
                attributes : ${p0?.attributes}
                """
            )

        }

        override fun onServiceLost(p0: NsdServiceInfo?) {
            Log.i("LANServiceDiscovery", "onServiceLost : $p0")
            onInfoChange("onServiceFound $p0")
        }
    }

    withContext(Dispatchers.IO) {
        // 先关掉之前的发现服务
        // nsdManager.stopServiceDiscovery(discoveryListener)
        nsdManager.discoverServices("_http._tcp.", NsdManager.PROTOCOL_DNS_SD, discoveryListener)
    }
}

/**
 * 服务连接
 * 一般是在服务发现之后, 根据 serviceName 进行连接以获取更详细的信息
 */
fun mdnsResolve(
    context: Context,
    nsdServiceInfo: NsdServiceInfo,
    onInfoChange: (info: String) -> Unit
) {
    val nsdManager: NsdManager = context.getSystemService(Context.NSD_SERVICE) as NsdManager

    val resolveListener = object : NsdManager.ResolveListener {
        override fun onResolveFailed(serviceInfo: NsdServiceInfo, errorCode: Int) {
            DebugUtil.errorLog("Resolve Failed. $errorCode")
            onInfoChange("Resolve Failed. $errorCode")
        }

        override fun onServiceResolved(serviceInfo: NsdServiceInfo) {
            DebugUtil.infoLog("Resolve Succeeded. $serviceInfo")
            onInfoChange(
                """
                Resolve Succeeded. 
                serviceName : ${serviceInfo.serviceName}
                serviceType : ${serviceInfo.serviceType}
                hostAddress : ${serviceInfo.host.hostAddress}
                port : ${serviceInfo.port}
                attributes : ${serviceInfo.attributes}
            """
            )
        }
    }

    nsdManager.resolveService(nsdServiceInfo, resolveListener)
}


@Preview(showSystemUi = true, showBackground = true)
@Composable
fun LANServiceDiscovery() {
    val context = LocalContext.current
    val infoList = remember {
        mutableStateListOf<String>()
    }

    val infoList2 = remember {
        mutableStateListOf<String>()
    }

    val scope = rememberCoroutineScope()


    Column {

        TextButton(onClick = {
            scope.launch {
                mdnsDiscovery(context) { info: String ->
                    infoList.clear()
                    infoList.add(info)
                }
            }
        }) {
            Text(text = "Start discover service")
        }

        for (info in infoList) {
            Text(text = info)
        }

        Divider()

        TextButton(onClick = {
            mdnsResolve(
                context,
                NsdServiceInfo().apply {
                    serviceName = "qiyue-application"
                    serviceType = "_http._tcp."
                }
            ) { info: String ->
                infoList2.clear()
                infoList2.add(info)
            }
        }) {
            Text(text = "Start resolve service")
        }

        for (info in infoList2) {
            Text(text = info)
        }

    }
}